home *** CD-ROM | disk | FTP | other *** search
- /*
- ** DBM -- General dbm management tool.
- ** Copyright (c) 1987 Lennart Lovstrand
- ** CIS Dept, Univ of Linkoping, Sweden
- **
- ** Use it, abuse it, but don't sell it.
- */
-
- #include "sendmail.h"
-
- #define DB_DIREXT ".dir"
- #define DB_PAGEXT ".pag"
-
- #ifndef lint
- static char SccsId[] = "@(#)dbm.c 2.2 (lel@ida.liu.se) 10/24/88";
- static char Rcsid[] = "@(#)$Id: dbm.c,v 1.12 1991/07/01 17:28:32 paul Exp $";
- #endif /* !lint */
-
- #define SAMECASE 0
- #define LOWERCASE 1
- #define UPPERCASE 2
-
- #define COMMENTCHAR '#'
- #define SENTENIEL "@@@"
-
- #define streq(s, t) (strcmp(s, t) == 0)
- #define MAKEDATUM(d, s) {(d).dptr = s; (d).dsize = strlen(s) + 1;}
- #define CHECKDATUM(d) if (Nullwarn && ((d).dsize == 0 || \
- (d).dptr[(d).dsize - 1] != '\0')) \
- fprintf(stderr, "[Warning: Entry not NULL terminated]\n");
-
- #ifdef __STDC__
- void opendbm(int, int);
- FILE * openfile(const char *, const char *);
- void closefile(FILE *);
- void parsefile(FILE *, FILE *);
- void loadfile(FILE *);
- char * scantoken(const char *);
- void casify(char *, int);
- #else /* !__STDC__ */
- # define const
- void opendbm();
- FILE * openfile();
- void closefile();
- void parsefile();
- void loadfile();
- char * scantoken();
- void casify();
- #endif /* __STDC__ */
- void closedbm();
- void do_clear();
- void do_delete();
- void do_dump();
- void do_fetch();
- void do_store();
- void do_parse();
- void do_make();
- void do_load();
- char * index();
-
- struct comtab {
- char *c_name;
- void (*c_func)();
- int LockType;
- } CommandTable[] = {
- {"clear", do_clear},
- {"delete", do_delete},
- {"dump", do_dump},
- {"fetch", do_fetch},
- {"load", do_load},
- {"make", do_make},
- {"parse", do_parse},
- {"store", do_store}
- };
-
- /* global arguments */
- int Argc;
- char **Argv;
-
- /* options */
- int Appending = FALSE;
- int Casing = SAMECASE;
- bool Debug = FALSE;
- char *Outfile = NULL;
- int Mode = 0644;
- char *Progname;
- char *Senteniel = NULL;
- int Storeflag = DBM_INSERT;
- bool Storewarn = TRUE;
- bool Nullwarn = FALSE;
- bool Valueonly = FALSE;
-
- /* Dbm globals */
- DBMFILE *Dbm;
- char *Dbmfile = NULL;
- int Dbmaccess;
- datum key, val;
-
- main(argc, argv)
- int argc;
- char **argv;
- {
- extern int optind;
- extern char *optarg;
- struct comtab *cmd;
- int c;
-
- Argc = argc;
- Argv = argv;
-
- Progname = Argv[0];
-
- while ((c = getopt(Argc, Argv, "ADILNRSUd:m:o:s:v")) != EOF)
- switch (c) {
- case 'A':
- Appending = TRUE;
- break;
- case 'D':
- Debug = TRUE;
- break;
- case 'I':
- Storeflag = DBM_INSERT;
- Storewarn = FALSE;
- break;
- case 'L':
- Casing = LOWERCASE;
- break;
- case 'N':
- Nullwarn = TRUE;
- break;
- case 'R':
- Storeflag = DBM_REPLACE;
- break;
- case 'S':
- if (Senteniel == NULL)
- Senteniel = SENTENIEL;
- break;
- case 'U':
- Casing = UPPERCASE;
- break;
- case 'd':
- Dbmfile = optarg;
- break;
- case 'm':
- if (optarg[0] == '0')
- (void) sscanf(optarg, "%o", &Mode);
- else {
- (void) sscanf(optarg, "%d", &Mode);
- if (Mode == 0) {
- (void) fprintf(stderr, "%s: non-numeric mode: %s\n",
- Progname, optarg);
- exit(1);
- }
- }
- break;
- case 'o':
- Outfile = optarg;
- break;
- case 's':
- Senteniel = optarg;
- break;
- case 'v':
- Valueonly = TRUE;
- break;
- default:
- (void) fprintf(stderr,
- "usage: %s [-ADILNRSU] [-d dbm_file] [-m mode] %s",
- Progname, "[-o output_file] [-v] command [args]\n");
- exit(1);
- }
-
- Argc -= optind;
- Argv += optind;
-
- if (Argc > 0) {
- for (cmd = CommandTable; cmd < &CommandTable[sizeof(CommandTable) /
- sizeof(*CommandTable)];
- cmd++)
- if (streq(*Argv, cmd->c_name)) {
- (*cmd->c_func)();
- exit(0);
- }
- (void) fprintf(stderr, "%s: unknown dbm command %s", Progname, *Argv);
- } else
- (void) fprintf(stderr, "%s: missing dbm command", Progname);
- (void) fprintf(stderr, ", use one of the following:\n");
- for (cmd = CommandTable; cmd < &CommandTable[sizeof(CommandTable) /
- sizeof(*CommandTable)]; cmd++)
- (void) fprintf(stderr, "%s%s", cmd == CommandTable ? "" : "\t",
- cmd->c_name);
- (void) fprintf(stderr, "\n");
- exit(3);
- }
-
- void
- opendbm(access, LockType)
- int access, LockType;
- {
- if (Dbmfile == NULL) {
- if (Argc > 1) {
- /* use last argument */
- Dbmfile = Argv[Argc-1];
- Argc--;
- } else {
- (void) fprintf(stderr, "%s: dbm file not specified\n", Progname);
- exit(3);
- }
- }
- Dbm = dbm_open(Dbmfile, access, Mode);
- if (Dbm == NULL) {
- char *filename = (char *) malloc((unsigned) strlen(Dbmfile) + 20);
- (void) sprintf(filename, "%s{%s,%s}", Dbmfile, DB_DIREXT, DB_PAGEXT);
- perror(filename);
- exit(4);
- }
- #ifndef GDBM
- if (flock(dbm_dirfno(Dbm), LockType) < 0) {
- (void) fprintf(stderr, "%s: cannot lock %s\n",
- Progname, Dbmfile);
- exit(3);
- }
- #endif /* !GDBM */
- Dbmaccess = access;
- }
-
- void
- closedbm()
- {
- if ((Dbmaccess & O_RDONLY) == 0 && Senteniel != NULL) {
- MAKEDATUM(key, Senteniel);
- if (dbm_store(Dbm, key, key, DBM_REPLACE) != 0) {
- (void) fprintf(stderr, "%s: could not store senteniel \"%s\"\n",
- Progname, Senteniel);
- perror(Progname);
- exit(5);
- }
- }
- #ifndef GDBM
- (void) flock(dbm_dirfno(Dbm), LOCK_UN);
- #endif /* !GDBM */
- dbm_close(Dbm);
- }
-
- FILE *
- openfile(filename, access)
- const char *filename;
- const char *access;
- {
- FILE *f;
-
- if (streq(filename, "-"))
- if (streq(access, "r"))
- return stdin;
- else
- return stdout;
- else {
- f = fopen(filename, access);
- if (f == NULL) {
- perror(filename);
- exit(4);
- }
- return f;
- }
- }
-
- void
- closefile(f)
- FILE *f;
- {
- if (f != stdin && f != stdout)
- (void) fclose(f);
- }
- /*
- ** DO_CLEAR -- Clear out database leaving it emtpy.
- */
-
- void
- do_clear()
- {
- if (Dbmfile != NULL) {
- opendbm(O_RDWR | O_CREAT | O_TRUNC, LOCK_EX);
- closedbm();
- }
- while (Argc > 1) {
- opendbm(O_RDWR | O_CREAT | O_TRUNC, LOCK_EX);
- closedbm();
- }
- }
-
-
- /*
- ** DO_DELETE -- Delete individual entries from the database.
- */
-
- void
- do_delete()
- {
- opendbm(O_RDWR | O_CREAT, LOCK_EX);
-
- for (Argc--, Argv++; Argc > 0; Argc--, Argv++) {
- casify(*Argv, Casing);
- MAKEDATUM(key, *Argv);
- if (dbm_delete(Dbm, key) != 0) {
- perror(*Argv);
- exit(5);
- }
- }
-
- closedbm();
- }
-
- /*
- ** DO_DUMP -- List all entries in the database.
- */
-
- void
- do_dump()
- {
- FILE *output;
-
- opendbm(O_RDONLY, LOCK_SH);
-
- if (Outfile == NULL)
- output = stdout;
- else
- output = openfile(Outfile, "w");
-
- for (key = dbm_firstkey(Dbm); key.dptr != NULL; key = dbm_nextkey(Dbm)) {
- val = dbm_fetch(Dbm, key);
- CHECKDATUM(key);
- CHECKDATUM(val);
- if (val.dptr == NULL)
- perror(key.dptr);
- else if (Valueonly)
- (void) fprintf(output, "%.*s\n", val.dsize, val.dptr);
- else
- (void) fprintf(output, "%.*s\t%.*s\n", key.dsize, key.dptr,
- val.dsize, val.dptr);
- }
- }
- /*
- ** DO_FETCH -- Lookup individual keys in the database.
- */
-
- void
- do_fetch()
- {
- char buf[BUFSIZ];
- register char *nl;
-
- opendbm(O_RDONLY, LOCK_SH);
-
- if (Argc == 1) {
- while (fgets(buf, sizeof(buf), stdin) != NULL) {
- if ((nl = index(buf, '\n')) != NULL)
- *nl = '\0';
- casify(buf, Casing);
- MAKEDATUM(key, buf);
- val = dbm_fetch(Dbm, key);
- CHECKDATUM(val);
- if (val.dptr == NULL)
- (void) printf("%s\t[NOT FOUND]\n", buf);
- else if (Valueonly)
- (void) printf("%.*s\n", val.dsize, val.dptr);
- else
- (void) printf("%s\t%.*s\n", buf, val.dsize, val.dptr);
- }
- }
- else
- for (Argc--, Argv++; Argc > 0; Argc--, Argv++) {
- casify(*Argv, Casing);
- MAKEDATUM(key, *Argv);
- val = dbm_fetch(Dbm, key);
- CHECKDATUM(val);
- if (val.dptr == NULL)
- (void) printf("%s\t[NOT FOUND]\n", *Argv);
- else if (Valueonly)
- (void) printf("%.*s\n", val.dsize, val.dptr);
- else
- (void) printf("%s\t%.*s\n", *Argv, val.dsize, val.dptr);
- }
-
- closedbm();
- }
-
- /*
- ** DO_STORE -- Insert individual entries into the database.
- */
-
- void
- do_store()
- {
- /* barf if # of args - 1 is even and no dbm file has been specified */
- if ((Argc & 1) == 1 && Dbmfile == NULL) {
- (void) fprintf(stderr, "%s: no dbm file specified\n", Progname);
- exit(3);
- }
-
- opendbm(O_RDWR | O_CREAT, LOCK_EX);
-
- for (Argc--, Argv++; Argc > 1; Argc -= 2, Argv += 2) {
- casify(Argv[0], Casing);
- MAKEDATUM(key, Argv[0]);
- MAKEDATUM(val, Argv[1]);
- if (dbm_store(Dbm, key, val, Storeflag) != 0) {
- extern int errno;
-
- if (errno != 0) {
- perror(Argv[0]);
- exit(5);
- } else if (Storewarn)
- (void) fprintf(stderr,
- "%s: duplicate key \"%s\" => \"%s\" ignored\n",
- Progname, Argv[0], Argv[1]);
- }
- }
- if (Argc > 0)
- (void) fprintf(stderr, "%s: no value for last key \"%s\"--ignored\n",
- Progname, Argv[0]);
-
- closedbm();
- }
-
- /*
- ** DO_PARSE -- Parse a textual database file and produce key-value
- ** pairs separated by a tab (suitable for input to the ``load''
- ** function).
- */
-
- void
- do_parse()
- {
- FILE *input, *output;
-
- if (Outfile == NULL)
- output = stdout;
- else
- output = openfile(Outfile, "w");
-
- if (Argc == 1)
- parsefile(stdin, output);
- else
- for (Argc--, Argv++; Argc > 0; Argc--, Argv++) {
- input = openfile(*Argv, "r");
- parsefile(input, output);
- closefile(input);
- }
- }
-
- /*
- ** DO_MAKE -- Parse the textual input and load the result into
- ** the database.
- */
-
- void
- do_make()
- {
- FILE *input, *pipin, *pipout;
- int pipes[2];
-
- opendbm(O_RDWR | O_CREAT | (Appending ? 0 : O_TRUNC), LOCK_EX);
-
- if (pipe(pipes) != 0) {
- perror("pipe");
- exit(9);
- }
- pipin = fdopen(pipes[0], "r");
- pipout = fdopen(pipes[1], "w");
-
- if (fork() == 0) {
- /* child process */
- (void) fclose(pipout);
-
- loadfile(pipin);
- } else {
- /* parent process */
- (void) fclose(pipin);
-
- if (Argc == 1)
- parsefile(stdin, pipout);
- else
- for (Argc--, Argv++; Argc > 0; Argc--, Argv++) {
- input = openfile(*Argv, "r");
- parsefile(input, pipout);
- closefile(input);
- }
- }
- closedbm();
- }
-
- /*
- ** DO_LOAD -- Load the dbm database from a text file. The input should
- ** be key-value pairs separated by a tab, each on a single line.
- */
-
- void
- do_load()
- {
- FILE *input;
-
- opendbm(O_RDWR | O_CREAT | (Appending ? 0 : O_TRUNC), LOCK_EX);
-
- if (Argc == 1)
- loadfile(stdin);
- else
- for (Argc--, Argv++; Argc > 0; Argc--, Argv++) {
- input = openfile(*Argv, "r");
- loadfile(input);
- closefile(input);
- }
- closedbm();
- }
-
- /*
- ** PARSEFILE, LOADFILE
- */
-
- void
- parsefile(input, output)
- FILE *input, *output;
- {
- char buf[BUFSIZ], *key, *val = NULL;
- register char *p;
-
- while (fgets(buf, sizeof(buf), input) != NULL) {
- if (buf[0] == COMMENTCHAR || buf[0] == '\n' || buf[0] == '\0')
- continue;
- p=buf;
- if (!isspace(buf[0])) {
- /* extract value */
- p = scantoken(buf);
- if (val != NULL)
- free(val);
- val = (char *) malloc((unsigned) (p - buf + 1));
- (void) strncpy(val, buf, p - buf);
- val[p - buf] = '\0';
- p++;
- }
- casify(buf, Casing);
- while ( *p != '\0') {
- while (*p != '\0' && isspace(*p)) p++;
- if (*p == '\0' || *p == COMMENTCHAR)
- break;
- key = p;
- p = scantoken(p);
- if (*p == COMMENTCHAR)
- *p = '\0';
- else if (*p != '\0')
- *p++ = '\0';
- (void) fprintf(output, "%s\t%s\n", key, val);
- }
- }
- }
-
- void
- loadfile(input)
- FILE *input;
- {
- char buf[BUFSIZ];
- register char *tab, *nl;
-
- while (fgets(buf, sizeof(buf), input) != NULL) {
- nl = index(buf, '\n');
- if (nl != NULL)
- *nl = '\0';
-
- tab = index(buf, '\t');
- if (tab == NULL) {
- (void) fprintf(stderr, "%s: missing tab in \"%s\"--ignored\n",
- Progname, buf);
- continue;
- }
- *tab++ = '\0';
- casify(buf, Casing);
- MAKEDATUM(key, buf);
- MAKEDATUM(val, tab);
- if (dbm_store(Dbm, key, val, Storeflag) != 0 && Storewarn) {
- extern int errno;
-
- if (errno != 0) {
- perror(buf);
- exit(5);
- } else if (Storewarn)
- (void) fprintf(stderr,
- "%s: duplicate key \"%s\" => \"%s\" ignored\n",
- Progname, buf, tab);
- }
- }
- }
-
- char *
- scantoken(p)
- register const char *p;
- {
- register bool quotedchar = FALSE, insidestring = FALSE, insideroute = FALSE;
-
- /* hidious address scanner */
- while (*p != '\0' && (quotedchar || insidestring || insideroute ||
- (*p != COMMENTCHAR && !isspace(*p)))) {
- /* special quote character handling */
- if (quotedchar)
- quotedchar = FALSE;
- else {
- quotedchar = (*p == '\\');
- if (!insidestring)
- if (*p == '<')
- insideroute = TRUE;
- else if (*p == '>')
- insideroute = FALSE;
- if (*p == '"')
- insidestring = !insidestring;
- }
- p++;
- }
-
- return (char *)p;
- }
-
- void
- casify(p, c)
- register char *p;
- int c;
- {
- switch (c) {
- case LOWERCASE:
- for (; *p != '\0'; p++)
- if (isupper(*p))
- *p = tolower(*p);
- break;
- case UPPERCASE:
- for (; *p != '\0'; p++)
- if (islower(*p))
- *p = toupper(*p);
- break;
- }
- }
-